﻿
#include "stdafx.h"

INLINE VOID AlphaBlendStandard(LPCWORD, LPWORD, LPCBYTE);
INLINE VOID AlphaBlendFullLevel(LPCWORD, LPWORD, LPCBYTE);
INLINE VOID AlphaBlend32LevelX86(LPCWORD, LPWORD, LPCBYTE);

//////////////////////////////////////////////////////////////////////////

INLINE VOID AlphaBlendStandard(LPCWORD src, LPWORD dest, LPCBYTE alpha)
{
	INT r, g, b;

	if (!*alpha)
		return;

	if (*alpha == COLOR_AMAX)
	{
		*dest = *src;
		return;
	}

	r = (COLOR_RVALUE(*src) * (*alpha) * COLOR_RMAX / COLOR_AMAX + COLOR_RVALUE(*dest) * (COLOR_RMAX - ((*alpha) * COLOR_RMAX / COLOR_AMAX))) / COLOR_RMAX;
	g = (COLOR_GVALUE(*src) * (*alpha) * COLOR_GMAX / COLOR_AMAX + COLOR_GVALUE(*dest) * (COLOR_GMAX - ((*alpha) * COLOR_GMAX / COLOR_AMAX))) / COLOR_GMAX;
	b = (COLOR_BVALUE(*src) * (*alpha) * COLOR_BMAX / COLOR_AMAX + COLOR_BVALUE(*dest) * (COLOR_BMAX - ((*alpha) * COLOR_BMAX / COLOR_AMAX))) / COLOR_BMAX;

	*dest = COLOR_MAKECOLOR(r, g, b);
}

INLINE VOID AlphaBlendFullLevel(LPCWORD src, LPWORD dest, LPCBYTE alpha)
{
	struct ENHCOLOR
	{
		WORD b:5;
		WORD g:6;
		WORD r:5;
	};

	INT r, g, b;

	if (!*alpha)
		return;

	if (*alpha == COLOR_AMAX)
	{
		*dest = *src;
		return;
	}

	const ENHCOLOR &src_s = reinterpret_cast<const ENHCOLOR &>(*src);
	ENHCOLOR &dest_s = reinterpret_cast<ENHCOLOR &>(*dest);

	r = (src_s.r * (*alpha) + dest_s.r * (255 - (*alpha))) >> 8;
	g = (src_s.g * (*alpha) + dest_s.g * (255 - (*alpha))) >> 8;
	b = (src_s.b * (*alpha) + dest_s.b * (255 - (*alpha))) >> 8;

	*dest = (r << 11) | (g << 5) | b;
}

INLINE VOID AlphaBlend32LevelX86Ex(BYTE alpha, LPWORD src, LPWORD dest)
{
	__asm
	{
		mov eax, src				// rgbrgb
		mov ebx, dest				// rgbrgb
		movzx	esi, alpha			// [M] esi = alpha


		mov ecx, eax	
		and	ecx, 07e0f81fh			// ecx = r.b.g. (07e0f81fh 11111000000111110000011111100000)
		and eax, 07E0F81Fh			// eax = .g.r.b (07E0F81Fh 00000111111000001111100000011111)

		mov edx, ebx	
		and	edx, 07e0f81fh			// ecx = R.B.G. (07e0f81fh 11111000000111110000011111100000)
		and ebx, 07E0F81Fh			// eax = .G.R.B (07E0F81Fh 00000111111000001111100000011111)

		sub	eax, ebx
		sub ecx, edx
		
		mul		esi					//  * alpha
		shr		eax, 5				// / alphalevel
		add		eax, ebx			// + dest


//		eax
	}

}

INLINE VOID AlphaBlend32LevelX86(LPCWORD src, LPWORD dest, LPCBYTE alpha)
{
	// 公式 dest = (src - dest) * (alpha / 8) / 32 + dest
	// [M] 存储器访问	应尽量减少内存访问次数(不过因为有Cache，在数据量小的时候效果不明显)
	// [L] 长运算操作	即乘除运算，CPU时钟占用率较高的指令
	// [W] 16位操作		动态执行(P6系列)处理器中对同一寄存器连续切换16/32位操作会存在延时，应尽可能避免
	// [B] 8位操作		尽可能的先清零32位寄存器再载入，同时尽量不改变高24位，否则会有延时
	// [J] 条件分支	针对CPU分支预测功能可以进行优化
	__asm
	{
		mov		esi, alpha			// [M]
		xor		ecx, ecx
		mov		cl, [esi]			// [M][B] ecx = alpha
		jcxz	quit				// [J]
		mov		edi, dest			// [M]
		mov		esi, src			// [M]
		add		ecx, 4				// ALPHA误差补正
		shr		ecx, 3				// 只保留32级（2的5次方）ALPHA

		// src/dest变形（为减少动态执行CPU的寄存器阻塞以及提高流水线效率而穿插进行）
		// 变形方式：
		//               rgb                               .g.r.b
		//     [RRRRR][GGGGGG][BBBBB] -> [00000][GGGGGG][00000][RRRRR][000000][BBBBB]
		movzx	edx, word ptr [esi]	// [M][W]
		movzx	esi, word ptr [edi]	// [M][W]
		mov		eax, edx			// ...rgb
		mov		ebx, esi			// ...rgb
		shl		eax, 16				// rgb...
		shl		ebx, 16				// rgb...
		or		eax, edx			// rgbrgb
		or		ebx, esi			// rgbrgb
		and		eax, 07e0f81fh		// .g.r.b
		and		ebx, 07e0f81fh		// .g.r.b

		// 混色
		sub		eax, ebx			// eax = src - dest
		mul		ecx					// [L] gxrxbx
		shr		eax, 5				// .gxrxb
		add		eax, ebx			// + dest
		and		eax, 07e0f81fh		// .g.r.b

		// 还原
		mov		ebx, eax
		shr		ebx, 16				// ....g.
		or		eax, ebx			// xxxrgb

		// 保存
		mov		[edi], ax			// [M][W]

quit:
	}
}

//////////////////////////////////////////////////////////////////////////
